#include "StdAfx.h"
#include "Lexico.h"


Lexico::Lexico(void)
{
}


Lexico::~Lexico(void)
{
	this->file.close();
}

Lexico::Lexico(string file_dir){
	file.open(file_dir, ios::in);
	this->linea=0;
	this->columna=0;
	this->token = new Token();
}

Token* Lexico::getNextToken(){
	
	if(this->file.is_open()){
		int estado = 0;
		string lexema ="";
		int tokenid =0;
		char nextcaracter = -1;
		while(this->file.good()){
			
			char caracter = this->file.peek() ;
				switch(estado){
			case 0:{

				if(caracter == -1){
					lexema ="$";
					//token = new Token(tokentype.fin_archivo,lexema,this->linea,this->columna);
					this->token->setCod(tokentype.fin_archivo);
					this->token->setLexema(lexema);
					this->token->setLinea(this->linea);
					this->token->setColumna(this->columna);

					return this->token;
				}else{
						if(isspace(caracter)){
							estado =1;
						}else{
							if(caracter == '+' ||caracter == '-' ||caracter == '(' ||caracter == ')' ||
							caracter == '^' ||caracter == '[' ||caracter == ']' ||caracter == ','||
							caracter == ':'||caracter == '.'||caracter == '=' || caracter == '*')
							{
								estado = 2;
							}else{
								if(caracter == '<' || caracter ==  '>' ){
								estado=3;
								}else{
									if(caracter == '/'){
									estado = 4;
									}else{
										if(isalpha(caracter)|| caracter=='_'){
										estado = 5;
										}else{
											if(isdigit(caracter)){
											estado = 6;
											}else{
												if(caracter == '\''){
												estado = 7;
												}else{
													if(caracter == '"'){
													estado = 8;
													}
												}
												
											}
											
										}
										
									}

									
								}
								
							}

							

						}
						
				}
				
				
				if(estado==0){
					
					stringstream out;
					out << "Error Lexico: Caracter No Valido" << endl;
					out << "Linea: ";
					out << this->linea;
					out << " Columna: ";
					out << this->columna<< endl;
					throw  exception(out.str().c_str());
				}
				
				
				break;}
			case 1:{
				this->file.get();
				if(caracter =='\n'|| caracter == '\r' || caracter == '\r\n'){
					lexema = caracter;
					//token = new Token(tokentype.enter,"Fin de Linea",this->linea,this->columna);
					this->token->setCod(tokentype.enter);
					this->token->setLexema("Fin de Linea");
					this->token->setLinea(this->linea);
					this->token->setColumna(this->columna);
				this->columna =0;
				this->linea++;

				return this->token;
				}else{
				this->columna++;
				}				
				estado = 0;
				break;}
			case 2:{
				caracter = this->file.get();
				lexema = caracter;
				this->columna++;
				tokenid =0;
				if(caracter == '+'){
					tokenid = tokentype.oprSuma;
				}
				if(caracter == '-'){
					tokenid = tokentype.oprResta;
				}
				if(caracter == '('){
					tokenid = tokentype.pntparIzq;
				}
				if(caracter == ')'){
					tokenid = tokentype.pntparDer;
				}
				if(caracter == '^'){
					tokenid = tokentype.oprExpo;
				}
				if(caracter == '['){
					tokenid = tokentype.pntcorIzq;
				}
				if(caracter == ']'){
					tokenid = tokentype.pntcorDer;
				}
				if(caracter == ','){
					tokenid = tokentype.pntComa;
				}
				if(caracter == ':'){
					tokenid = tokentype.pntDosPuntos;
				}
				if(caracter == '.'){
					tokenid = tokentype.pntPunto;
				}
				if(caracter == '='){
					tokenid = tokentype.oprIgual;
				}
				if(caracter == '*'){
					tokenid = tokentype.oprMult;
				}
				//token = new Token(tokenid,lexema,this->linea,this->columna);
					this->token->setCod(tokenid);
					this->token->setLexema(lexema);
					this->token->setLinea(this->linea);
					this->token->setColumna(this->columna);
				return this->token;
				break;}
			case 3:{
				caracter = this->file.get();
				lexema = caracter;
				this->columna++;
				tokenid =0;
				nextcaracter = this->file.peek();
				switch(caracter){
				case '<':		
					switch(nextcaracter){
					case '=':
						caracter = this->file.get();
						this->columna++;
						tokenid = tokentype.oprMenorIgual;
						lexema.append(1,caracter);
					break;
					case '-':
						caracter = this->file.get();
						this->columna++;
						tokenid = tokentype.oprAsig;
						lexema.append(1,caracter);
						break;
					case '>':
						caracter = this->file.get();
						this->columna++;
						tokenid = tokentype.oprDist;
						lexema.append(1,caracter);
						break;

					default:
						tokenid = tokentype.oprMenor;
						break;
					
					}
				break;
				case '>':
					switch(nextcaracter){
					case '=':
						caracter = this->file.get();
						this->columna++;
						tokenid = tokentype.oprMayorIgual;
						lexema.append(1,caracter);
					break;

					default:
						tokenid = tokentype.oprMayor;
						break;
					
					}

					break;


				}
				//token = new Token(tokenid,lexema,this->linea,this->columna);
				this->token->setCod(tokenid);
					this->token->setLexema(lexema);
					this->token->setLinea(this->linea);
					this->token->setColumna(this->columna);
				return this->token;
				break;}
			case 4:{
				caracter = this->file.get();
				lexema = caracter;
				char c =-1;
				switch(this->file.peek()){
					case '/':
				
						while((c=this->file.peek()) != '\n' && (c=this->file.peek()) != '\r'&& (c=this->file.peek())!= '\r\n' ){
							c = this->file.get();
						}
						this->columna=0;
						this->linea++;
						estado = 0;

					break;
					case '*':{
						int commentL = this->linea;
						int commentC = this->columna;
						string fincomment = "";
						c = this->file.get();
						this->columna++;
						c = this->file.get();
						this->columna++;
						
						fincomment.append(1,c);
						fincomment.append(1,this->file.peek());

						while(fincomment != "*/" && c != -1 ){
							
							if(c =='\n'|| c == '\r' || c == '\r\n' ){
							this->columna =0;
							this->linea++;
							}else{
								this->columna++;
							}
							c = this->file.get();
							fincomment = "";
							fincomment.append(1,c);
							fincomment.append(1,this->file.peek());
							
						}
						
						if(c == -1){
							stringstream out;
							out<< "Error Lexico: se esperaba fin de Comentario */"<< endl;
							out<< "Linea: ";
							out<< commentL;
							out<< " Columna: ";
							out<< commentC << endl;
							throw  exception(out.str().c_str());
						}else{
							this->file.get();
							estado = 0;
						}
						break;}
					default:
						this->token->setCod(tokentype.oprDiv);
					this->token->setLexema(lexema);
					this->token->setLinea(this->linea);
					this->token->setColumna(this->columna);
					return this->token;
						//return token = new Token(tokentype.oprDiv,lexema,this->linea,this->columna);
						break;
				}
				

				break;}
			case 5:{
				lexema.append(1,this->file.get());
				this->columna++;
				char c = -1;
				if(isalnum(c=this->file.peek())||(c=this->file.peek())=='_'){
					estado = 5;
				}else{
					tokentype.it = tokentype.find(lexema);
				if(tokentype.it != tokentype.reservadas.end()){
					//token = new Token(tokentype.it->second,lexema,this->linea,this->columna);
					this->token->setCod(tokentype.it->second);
					this->token->setLexema(lexema);
					this->token->setLinea(this->linea);
					this->token->setColumna(this->columna);
					return this->token;
				}else{
					//token = new Token(tokentype.litIdentificador,lexema,this->linea,this->columna);
					this->token->setCod(tokentype.litIdentificador);
					this->token->setLexema(lexema);
					this->token->setLinea(this->linea);
					this->token->setColumna(this->columna);
					return this->token;
				}
				}

				

				break;}
			case 6:{
				lexema = this->file.get();
				this->columna++;
				char d =-1;
				while(isdigit((d=this->file.peek()))){
					lexema.append(1,d);
					this->columna++;
					this->file.get();
				}
				if(!isspace(d) && d!=')'&& d!= '('&& d!= '[' && d!= ']' && d!= ',' && d!= '+' && d!= '-' && d!= '*' && d!= '/' && d!= '<' && d!= '>' && d!= '^' && d!= ':' && d!= '='  && d!= -1){
					if(d== '.'){
						lexema.append(1,d);
						this->file.get();
						if(!isspace(this->file.peek())){
							while(isdigit((d=this->file.peek()))){
								lexema.append(1,d);
								this->columna++;
								this->file.get();
							}
							if(!isspace(d) && d!=')'&& d!= '('&& d!= '[' && d!= ']' && d!= ',' && d!= '+' && d!= '-' && d!= '*' && d!= '/' && d!= '<' && d!= '>' && d!= '^' && d!= ':' && d!= '=' && d!= -1){
								stringstream out;
								out<<"Error Lexico: Se esperaba digitos no caracteres"<<endl;
								out << "Linea: ";
								out << this->linea;
								out << " Columna: ";
								out << this->columna<< endl;
								throw exception(out.str().c_str());
							}else{
								//token = new Token(tokentype.litNumeroReal,lexema,this->linea,this->columna);
								this->token->setCod(tokentype.litNumeroReal);
								this->token->setLexema(lexema);
								this->token->setLinea(this->linea);
								this->token->setColumna(this->columna);
								return this->token;
							}
						}
					}else{

						stringstream out;
						out<<"Error Lexico: Se esperaba un . o mas digitos"<<endl;
						out << "Linea: ";
						out << this->linea;
						out << " Columna: ";
						out << this->columna<< endl;
						throw exception(out.str().c_str());

					}
				}

				lexema = lexema.substr(0,lexema.size());
				//token = new Token(tokentype.litNumeroEntero,lexema,this->linea,this->columna);
				this->token->setCod(tokentype.litNumeroEntero);
								this->token->setLexema(lexema);
								this->token->setLinea(this->linea);
								this->token->setColumna(this->columna);
								return this->token;

				break;}
			case 7:{
				lexema = this->file.get();
				this->columna++;
				if(this->file.peek()!='\''){
				lexema.append(1,this->file.get());
				this->columna++;
				}else{
					stringstream out;
								out<<"Error Lexico: No Pueden ir Dos Commilas Simples juntas"<<endl;
								out << "Linea: ";
								out << this->linea;
								out << " Columna: ";
								out << this->columna<< endl;
								throw  exception(out.str().c_str());
				}
				if(this->file.peek() == '\''){
					this->columna++;
					lexema.append(1,this->file.get());
					//token = new Token(tokentype.litCaracter,lexema,this->linea,this->columna);
					this->token->setCod(tokentype.litCaracter);
					this->token->setLexema(lexema);
					this->token->setLinea(this->linea);
					this->token->setColumna(this->columna);

					return this->token;
				}else{

								stringstream out;
								out<<"Error Lexico: Se esperaba comilla simple"<<endl;
								out << "Linea: ";
								out << this->linea;
								out << " Columna: ";
								out << this->columna<< endl;
								throw  exception(out.str().c_str());
				}
				break;}
			case 8:{
				lexema = this->file.get();
				this->columna++;
				while(this->file.peek() != '"' && this->file.peek() != '\n' && this->file.peek() != '\r' && this->file.peek() != '\r\n' && this->file.peek() != -1){
					
					lexema.append(1,this->file.get());
					this->columna++;
				 
				}
				if(this->file.peek()=='"'){
					lexema.append(1,this->file.get());
					this->columna++;
					//token = new Token(tokentype.litCadena,lexema,this->linea,this->columna);

					this->token->setCod(tokentype.litCadena);
					this->token->setLexema(lexema);
					this->token->setLinea(this->linea);
					this->token->setColumna(this->columna);

					return this->token;
				}else{
						
						stringstream out;
						out<<"Error Lexico: Se esperaba comilla doble"<<endl;
						out << "Linea: ";
						out << this->linea;
						out << " Columna: ";
						out << this->columna<< endl;
						throw  exception(out.str().c_str());
								
								
				}
				break;}	
			
			}

			

		}
			
		lexema ="$";
		//token = new Token(tokentype.fin_archivo,lexema,this->linea,this->columna);

		this->token->setCod(tokentype.fin_archivo);
					this->token->setLexema(lexema);
					this->token->setLinea(this->linea);
					this->token->setColumna(this->columna);
		return this->token;
		

	}else{
		stringstream out;
		out<<"Error Lexico: No se Pudo Abrir El Archivo"<<endl;
		throw exception(out.str().c_str());
	}


}

void Lexico::fileClose(){
	this->file.close();
}